package com.yeyaomai.dksns.flowis.quartz;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.query.Criteria;

import com.yeyaomai.dksns.flowis.dao.DetailDao;
import com.yeyaomai.dksns.flowis.dao.UserReturnRateDao;
import com.yeyaomai.dksns.flowis.dao.VisitDepthDao;
import com.yeyaomai.dksns.flowis.domain.UserReturnRate;
import com.yeyaomai.dksns.flowis.domain.VisitDepth;
import com.yeyaomai.dksns.flowis.domain.flowisdetail.FlowisStatDetailDTO;
import com.yeyaomai.dksns.flowis.util.CollectionNames;
import com.yeyaomai.dksns.flowis.util.Globals;
import com.yeyaomai.dksns.flowis.util.VelocityToolDateUtils;

//zuoshuai@yeyaomai.net
public class CustomerLoyaltyExecutor {
	@Resource
	private DetailDao detailDao;
	@Resource
	private UserReturnRateDao userReturnRateDao;
	@Resource
	private VisitDepthDao visitDepthDao;

	final Logger logger = Logger.getLogger("quartz");

	public static void main(String[] args) {
		// test...
		// String date = VelocityToolDateUtils.getDateRange(new Date(), 1);
		// System.out.println(date);
	}

	public void executeCustomerLoyalty() {
		String from = null;// "2012-01-01";
		String to = null;// "2013-01-01";

		String[] dates = VelocityToolDateUtils.getDateRange(new Date(), 1).split(",");
		from = dates[0];
		to = dates[1];

		try {
			GroupByResults<VisitDepth> visitDepthList = groupDepth(from, to);
			// key =深度 value=独立访客
			Map<Integer, Integer> depthMap = new HashMap<Integer, Integer>();
			// 构造访问深度map
			for (VisitDepth visitDepth : visitDepthList) {
				int depth = visitDepth.getDepth();
				// 构造map
				if (!depthMap.containsKey(depth)) {
					depthMap.put(depth, 1);
				} else {
					int value = depthMap.get(depth);
					value += 1;
					depthMap.put(depth, value);
				}
				// 完毕
			}

			// 写库
			for (Entry<Integer, Integer> entry : depthMap.entrySet()) {
				VisitDepth visitDepth = new VisitDepth();

				visitDepth.setDepth(entry.getKey());
				visitDepth.setUniqueHost(entry.getValue());
				visitDepth.setGmtCreate(Globals.FORMAT_TYPE_A.parse(dates[0]));
				visitDepthDao.add(visitDepth);
				visitDepth = null;
			}

			GroupByResults<UserReturnRate> returnRateList = groupReturn(from, to);

			// 回头率
			for (UserReturnRate rate : returnRateList) {
				UserReturnRate userReturnRate = new UserReturnRate();

				int returnNumber = rate.getReturnNumber();
				// 计算独立ip
				int ip = countIp(from, to, returnNumber);
				// 计算独立访客
				int uniqueHost = countUnicHost(from, to, returnNumber);
				// 计算pv量
				int pv = rate.getReturnRate();

				userReturnRate.setIp(ip);
				userReturnRate.setUniqueHost(uniqueHost);
				userReturnRate.setReturnRate(returnNumber);
				userReturnRate.setPv(pv);

				userReturnRate.setGmtCreate(Globals.FORMAT_TYPE_A.parse(dates[0]));
				userReturnRateDao.add(userReturnRate);

				userReturnRate = null;
			}
			logger.info("#########用户忠诚度之访问深度执行完毕，写入数据" + depthMap.size() + "条###############::executeCustomerLoyalty()"
					+ new Date());
			logger.info("#########用户忠诚度之回头率执行完毕，写入数据" + returnRateList.getKeys() + "条##########::executeCustomerLoyalty()"
					+ new Date());
		} catch (Exception e) {
			logger.info("#########用户忠诚度统计执行失败##########::executeCustomerLoyalty()" + new Date());
			e.printStackTrace();
		}
	}

	// 计算独立访客
	private int countUnicHost(String st, String et, int returnNumber) {
		String mapFunction = "{ ip: 0}";
		String reduceFunction = "function(key,values) {values.ip+=1}";
		Criteria criteria = Criteria.where("ip").ne("null").and("access_date").gte(st).lt(et).and("returnNumber")
				.is(returnNumber);
		String[] groups = { CollectionNames.COOKIEID };

		return detailDao.groups(criteria, mapFunction, reduceFunction, FlowisStatDetailDTO.class, groups).getKeys();

	}

	// 计算独立ip
	private int countIp(String st, String et, int returnNumber) {
		String mapFunction = "{ ip: 0}";
		String reduceFunction = "function(key,values) {values.ip+=1}";
		Criteria criteria = Criteria.where("ip").ne("null").and("access_date").gte(st).lt(et).and("returnNumber")
				.is(returnNumber);
		return detailDao.group(criteria, CollectionNames.IP, mapFunction, reduceFunction, FlowisStatDetailDTO.class)
				.getKeys();
	}

	/**
	 * 访问深度
	 * 
	 * @param st
	 * @param et
	 * @return
	 */
	public GroupByResults<VisitDepth> groupDepth(String st, String et) {
		String mapFunction = "{depth:0}";
		String reduceFunction = "function(key,values){values.depth +=1}";
		Criteria criteria = Criteria.where("access_date").gte(st).lt(et);
		String[] groups = { CollectionNames.COOKIEID, CollectionNames.VISITCOUNT };
		return detailDao.groups(criteria, mapFunction, reduceFunction, VisitDepth.class, groups);

	}

	/**
	 * 回头率
	 * 
	 * @param st
	 * @param et
	 * @return
	 */
	public GroupByResults<UserReturnRate> groupReturn(String st, String et) {
		String mapFunction = "{returnRate:0}";
		String reduceFunction = "function(key,values){values.returnNumber,values.returnRate +=1}";
		Criteria criteria = Criteria.where("access_date").gte(st).lt(et);
		String[] groups = { CollectionNames.RETURN_NUMBER };
		return detailDao.groups(criteria, mapFunction, reduceFunction, UserReturnRate.class, groups);

	}
}
